/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ConfigurationPanel.java
 *
 * Created on 19/11/2012, 12:40:44
 */
package GUI;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import thecliffproblem.Board;

/**
 *
 * @author Jaime
 */
public class ConfigurationPanel extends javax.swing.JPanel {

    private Board board;
    private long delay = 100;
    private Lock lock;
    private boolean runningEpisode = false;
    private ApplicationPanel app;
    private boolean keepRunning = true;
    private int numberOfCurrentEpisodes = 0;
    private int numberOfCurrentSteps = 0;
    
    /** Creates new form ConfigurationPanel */
    public ConfigurationPanel(Board board, ApplicationPanel app) {
        initComponents();
        this.board = board;
        lock = new ReentrantLock();
        this.app = app;
        currentDelayLabel.setText(String.valueOf(delay));
        
    }
    
    private void setDelay(int delay)
    {
        //lock.lock();
        try {
            this.delay = delay;
            currentDelayLabel.setText(String.valueOf(delay));
        } finally {
            //lock.unlock();
        }
    }
    
    private void runEpisode()
    {
        if(runningEpisode)
            return;
        
        runningEpisode = true;
        runSingleEpisode();
        runningEpisode = false;
    }
        
    private void runSingleEpisode()
    {
        try {
            lock.lock();
            int steps = board.nextEpisode(true, delay);
            numberOfCurrentEpisodes++;
            numberOfCurrentEpisodesLabel.setText(numberOfCurrentEpisodes+"");
            numberOfCurrentSteps += steps;
            numberOfCurrentStepsLabel.setText(numberOfCurrentSteps+"");
            
        } catch (InterruptedException ex) {
            JOptionPane.showMessageDialog(this, "An error has happened, exiting.",
                    "ERROR!", JOptionPane.WARNING_MESSAGE);
            System.exit(1);
        }
        finally
        {
            lock.unlock();
        }
        
        
        
    }
    
    private void runEpisodes(int numberOfEpisodes)
    {
        if(runningEpisode)
            return;
        runningEpisode = true;
        keepRunning = true;
        for(int i = 0; i < numberOfEpisodes; i++)
        {
            runSingleEpisode();
            if(!keepRunning)
                break;
        }
            
        
        runningEpisode = false;
        
    }

    

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        numberOfEpisodesField = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        jButton2 = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        delayField = new javax.swing.JTextField();
        jButton3 = new javax.swing.JButton();
        jButton4 = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        currentDelayLabel = new javax.swing.JLabel();
        stopButton = new javax.swing.JButton();
        jLabel4 = new javax.swing.JLabel();
        numberOfCurrentEpisodesLabel = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        numberOfCurrentStepsLabel = new javax.swing.JLabel();

        setBorder(javax.swing.BorderFactory.createTitledBorder("Configuration"));

        jButton1.setText("Run Episode");
        jButton1.setToolTipText("Run one episode with the current configuration.");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        numberOfEpisodesField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                numberOfEpisodesFieldActionPerformed(evt);
            }
        });

        jLabel1.setText("# of Episodes");

        jButton2.setText("Run Episodes");
        jButton2.setToolTipText("Run many episodes with current configuration, as configured in the text field to the left.");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jLabel2.setText("Delay (milliseconds):");

        jButton3.setText("Set delay");
        jButton3.setToolTipText("Set the delay between steps of an episode in milliseconds");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        jButton4.setText("Reset");
        jButton4.setToolTipText("Start over the simulation.");
        jButton4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton4ActionPerformed(evt);
            }
        });

        jLabel3.setText("Current delay:");

        currentDelayLabel.setText("100");

        stopButton.setText("Stop");
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        jLabel4.setText("# of episodes so far:");

        numberOfCurrentEpisodesLabel.setText("0");

        jLabel5.setText("# of steps so far:");

        numberOfCurrentStepsLabel.setText("0");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(83, 83, 83)
                                .addComponent(jLabel2))
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jButton1)))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel1)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(numberOfEpisodesField, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(jButton2)))
                                .addGap(41, 41, 41)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(stopButton)
                                    .addComponent(jButton4)))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(delayField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(jButton3)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(jLabel3))
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(jLabel5)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(numberOfCurrentStepsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE))))))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(127, 127, 127)
                        .addComponent(jLabel4)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(numberOfCurrentEpisodesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(21, 21, 21)
                .addComponent(currentDelayLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(249, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(numberOfCurrentEpisodesLabel)
                    .addComponent(jLabel5)
                    .addComponent(numberOfCurrentStepsLabel))
                .addGap(22, 22, 22)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(delayField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton3)
                    .addComponent(jLabel3)
                    .addComponent(currentDelayLabel))
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(jButton4)
                        .addGap(18, 18, 18)
                        .addComponent(stopButton))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(36, 36, 36)
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(numberOfEpisodesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jButton2)
                            .addComponent(jButton1))))
                .addContainerGap(36, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        // TODO add your handling code here:
        //runEpisode();
        (new Thread(new BoardRunnable(1))).start();
        
    }//GEN-LAST:event_jButton1ActionPerformed

    private void numberOfEpisodesFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numberOfEpisodesFieldActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_numberOfEpisodesFieldActionPerformed

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        // TODO add your handling code here:
        
        int numberEpisodes = getNumberEpisodes();
        
        if(numberEpisodes == -1)
            return;
        
        //runEpisodes(numberEpisodes);
        (new Thread(new BoardRunnable(numberEpisodes))).start();
        
    }//GEN-LAST:event_jButton2ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
        // TODO add your handling code here:
        //lock.lock();
        //try {
            int theDelay = getDelay();
            if(theDelay == -1)
                return;
            setDelay(theDelay);
            JOptionPane.showMessageDialog(this, "Delay set to "+theDelay+".");
        //} finally {
          //  lock.unlock();
        //}
        
    }//GEN-LAST:event_jButton3ActionPerformed

    private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton4ActionPerformed
        // TODO add your handling code here:
        
        if(runningEpisode)
        {
            JOptionPane.showMessageDialog(null, "Cannot reset while running!");
            return;
        }
        
        int confirm = JOptionPane.showConfirmDialog(this, "Are you sure you want to"
                + " reset this simulation (this operation cannot be undone)?", "RESET?", 
                JOptionPane.YES_NO_OPTION);
        if(confirm == JOptionPane.YES_OPTION)
        {
            board.reset();
            numberOfCurrentEpisodes=0;
            numberOfCurrentEpisodesLabel.setText("0");
            numberOfCurrentSteps=0;
            numberOfCurrentStepsLabel.setText("0");
        }
    }//GEN-LAST:event_jButton4ActionPerformed

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
        // TODO add your handling code here:
        
        keepRunning = false;
        
    }//GEN-LAST:event_stopButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel currentDelayLabel;
    private javax.swing.JTextField delayField;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JButton jButton4;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel numberOfCurrentEpisodesLabel;
    private javax.swing.JLabel numberOfCurrentStepsLabel;
    private javax.swing.JTextField numberOfEpisodesField;
    private javax.swing.JButton stopButton;
    // End of variables declaration//GEN-END:variables

    private int getNumberEpisodes() {
        
        try
        {
            int num =  Integer.parseInt(numberOfEpisodesField.getText());
            
            if(num > 0)
                return num;
            
            throw new NumberFormatException();
        }
        catch(Exception e)
        {
            JOptionPane.showMessageDialog(this, "Invalid number of episodes.");
            return -1;
        }
        
    }
    
    private int getDelay() {
        
        try
        {
            int num =  Integer.parseInt(delayField.getText());
            
            if(num >= 0)
                return num;
            
            throw new NumberFormatException();
        }
        catch(Exception e)
        {
            JOptionPane.showMessageDialog(this, "Invalid delay.");
            return -1;
        }
        
    }
    
    private class BoardRunnable implements Runnable
    {
        private int numberOfEpisodes;
        
        public BoardRunnable(int numberOfEpisodes)
        {
            this.numberOfEpisodes = numberOfEpisodes;
        }
        
        @Override
        public void run() {
            if(numberOfEpisodes == 1)
            {
                runEpisode();
            }
            else
            {
                runEpisodes(numberOfEpisodes);
            }
        }
        
    }
    
}
